<?php

namespace app\api\service;

use app\api\extra\consts\UserConst;
use app\api\model\wanlshop\Goods;
use app\common\model\MoneyLog;
use app\common\model\User;
use app\common\model\UserExtra;
use think\Db;
use think\Log;
use think\Queue;

class PromoteService
{
    private static $instance;

    public static function getInstance()
    {
        if (!(self::$instance instanceof self)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function participation($order_id)
    {
        try {
            // 检查订单是否存在
            $model_order = model('app\api\model\wanlshop\Order');
            $order_info = $model_order->find($order_id);

            if (!$order_info || $order_info['shop_id'] != config('oem.OrderShopPrefix')) {
                return false;
            }

            // 获取目标分类下的商品ID列表
            $category_id = (int)config('oem.CategoryIdPrefix');
            if ($category_id <= 0) {
                throw new \InvalidArgumentException('Invalid CategoryIdPrefix configuration.');
            }

            $goods_category = model('app\api\model\wanlshop\Goods');
            $goods_ids = $goods_category
                ->where('category_id', $category_id)
                ->column('id');

            if (!is_array($goods_ids)) {
                return true;
            }

            $goods_ids = array_values($goods_ids);
            if (empty($goods_ids)) {
                return true;
            }

            // 统计符合条件的商品总数量
            $model_order_goods = model('app\api\model\wanlshop\OrderGoods');
            $totalNumber = $model_order_goods
                ->where('order_id', $order_info['id'])
                ->whereIn('goods_id', $goods_ids)
                ->sum('number');

            if ($totalNumber > 1) {
                return false;
            }

            // 计算应得积分
            $order_goods_price = $model_order_goods
                ->where('order_id', $order_info['id'])
                ->sum('price');

            // $goods_id = $model_order_goods
            //     ->where('order_id', $order_info['id'])
            //     ->find('goods_id');
             $goods_id = $model_order_goods
                ->where('order_id', $order_info['id'])
                ->find();
            $get_order_star_level = $this->getOrderStarLevel($goods_id->goods_id);
            // $get_order_star_level = $this->getOrderStarLevel($order_goods_price);
            if ($get_order_star_level == 0) {
                return ['code' => 10001, 'msg' => '当前等级无法购买'];
            }

            $user = User::get($order_info['user_id']);
            if (($get_order_star_level - $user->star) != 1) {
                return ['code' => 10001, 'msg' => '当前等级无法购买'];
            }

            $get_score = $this->getOrderScore($order_goods_price);

            // 更新用户星级
            Db::startTrans();
            try {
                $user->star = $get_order_star_level;
                $user->star_update_time = time();
                if ($get_order_star_level == 1) {
                    $user->lamp = 1;
                    $user->first_lamp_time = time();
                    $user->lamp_update_time = time();
                }
                $user->product_orders = bcadd($user->product_orders, $order_goods_price);

                $get_user_extra = UserExtra::where('user_id', $user['id'])->find();
                if (!$get_user_extra) {
                    Db::rollback();
                    return false;
                }
                $get_user_extra->star = $get_order_star_level;

                $direct_push = User::get($user->direct_push);
                if ($get_order_star_level == 1) {
                    $this->handleDirectPushReward($direct_push, $get_score, $order_info['id'], $user);
                } else {
                    $this->handleUpgradeReward($direct_push, $get_order_star_level, $get_score, $order_info['id'], $user);
                }

                $get_user_extra->save();
                $user->save();

                // 更新伞下订单统计
                $this->upgradeAllOrder($user->pid, $order_goods_price);
                
                if($get_order_star_level == 13){
                    $this->updateUserPromotionMoney($order_info['user_id'],$order_goods_price);
                }

                Db::commit();
            } catch (\Exception $e) {
                Db::rollback();
                Log::error("升级错误的原因:" . $e->getMessage());
                return false;
            }

            return true;
        } catch (\Exception $e) {
            Log::error("升级错误的原因: " . $e->getMessage());
            return false;
        }
    }

    private function handleDirectPushReward($user_extra, $score, $order_id, $user)
    {
        if (!$user_extra) {
            return;
        }
        $score = 121;
//        $myLeaderIdArr = $this->getMyLeaderIdArr($user->id);
//        db("user")->where("id","in",$myLeaderIdArr)->where("lamp",1)->where("star",13)->inc("promotion_money",50)->update(["updatetime"=>time()]);

        $extra = UserExtra::where('user_id', $user_extra->id)->find();
        if (!$extra) {
            return;
        }

        $extra->score = bcadd($extra->score, $score, 2);
        $user_extra->score = bcadd($user_extra->score, $score, 2);
        UserService::getInstance()->money($score, $user_extra->id, $user->username . ' - 升级' . 1 . '星' . config('oem.DirectPushName'), 'upgrade', $order_id);
        $user_extra->money = bcadd($user_extra->money, $score, 2);

        $new_score = 50;
        $users = $this->currentUser($extra,12);
        $insert = [
            "user_id"       => $users["id"],
            "money"         => $new_score,
            "before"        => $user["money"],
            "after"         => bcadd($user["money"],$new_score),
            "memo"          => $user->username . ' - 升级' . 1 . '星;顶层服务提成!',
            "service_ids"   => "",
            "type"          => "upgrade",
            "createtime"    => time(),
        ];
        db("user")->where("id",$users["id"])->inc("money",$new_score)->inc("score",$new_score)->update(["updatetime"=>time()]);
        db("user_money_log")->insert($insert);
        $extra->save();
        $user_extra->save();
    }

    private function handleUpgradeReward($direct_push, $star_level, $score, $order_id, $user)
    {

        Db::startTrans();
        try {

            $sub_score = $this->getOrderSubScore($star_level);
            $this->salesCommissions($direct_push, $star_level, $sub_score, $order_id, $user->username);
            if($star_level == 2){
                $user_extra = $this->currentUser($user, $star_level);
            }else{
                $user_extra = $this->currentUserStar($user, $star_level);
            }

            if (!$user_extra) {
                Db::rollback();
                return;
            }
            $this->promoteUserScore($user_extra, $star_level, bcsub($score, $sub_score), $order_id, $user["username"]);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            Log::error("处理升级奖励错误的原因 (Order ID: {$order_id}): " . $e->getMessage());
        }
    }
    /**
     * @param $user
     * @param $star_level
     * @return User|mixed
     * @throws \think\exception\DbException
     */
    private function currentUser($user, $star_level)
    {
        // 输入参数验证
        if (empty($user) || !isset($user->pid) || $star_level < 0) {
            return $user;
        }

        $firstIdPrefix = config('oem.FirstIdPrefix');
        if (!is_string($firstIdPrefix)) {
            throw new \InvalidArgumentException('FirstIdPrefix must be a string');
        }

        $currentUser = $user;

        for ($i = 1; $i < $star_level; $i++) {
            if (empty($currentUser) || !isset($currentUser->pid)) {
                break;
            }

            $star_user = User::where('id', $currentUser->pid)
                ->find();

            // 终止条件1：父用户不存在
            if (!$star_user) {
                break;
            }

            // 如果父用户的 lamp 不为 1，则增加一次循环
            if ($star_user->lamp != UserConst::NORMAL) {
                $i--; // 减少一次循环计数，以便多循环一次
            }

            $currentUser = $star_user;
        }

        return $currentUser;
    }

    public function currentUserStar($user, $star_level){
        // 输入参数验证
        if (empty($user) || !isset($user["pid"]) || $star_level < 0) {
            return $user;
        }

        $firstIdPrefix = config('oem.FirstIdPrefix');
        if (!is_string($firstIdPrefix)) {
            throw new \InvalidArgumentException('FirstIdPrefix must be a string');
        }

        $my_star = $star_level - 1;

        $memo = $user["username"] . " - " . $my_star . "星管理提成";

        $new_user_id = db("user_money_log")->where("memo",$memo)->order("id desc")->value("user_id");

        if(!$new_user_id){
            $currentUser = $this->currentUser($user,$star_level);
        }else{
            $user = db("user")->where("id",$new_user_id)->find();
            $currentUser = $this->getLevelUser($user);
        }

        return $currentUser;
    }

    public function getLevelUser($user){
        $users = db("user")->where("id",$user["pid"])->find();
        if(!$users){
            return $user;
        }
        if ($users["lamp"] == 1){
            return $users;
        }else{
            return $this->getLevelUser($users);
        }
    }


    /**
     * 计算订单得分
     * @param float $order_goods_price 订单商品价格
     * @return float 计算得到的得分
     */
    private function getOrderScore($order_goods_price)
    {
        $subOrderPrefix = config('oem.SubOrderPrefix');
        $munOrderPrefix = config('oem.MulOrderPrefix');

        if (!is_numeric($subOrderPrefix) || !is_numeric($munOrderPrefix)) {
            throw new \InvalidArgumentException('Invalid configuration values for SubOrderPrefix or MunOrderPrefix.');
        }

        // 验证输入是否为有效数值
        if (!is_numeric($order_goods_price)) {
            throw new \InvalidArgumentException('Invalid order_goods_price value.');
        }

        // 处理边界条件
        if ($order_goods_price <= $subOrderPrefix) {
            return 0;
        }

        // 计算分数
        $score = bcmul(bcsub((string)$order_goods_price, (string)$subOrderPrefix, 2), (string)$munOrderPrefix, 2);
        return $score;
    }


    public function getAncestors($maxLevel)
    {
        $ancestors = [];
        $current = $this;

        for ($i = 0; $i < $maxLevel; $i++) {
            $current = $current->pid ? User::get($current->pid) : null;
            if (!$current) break;
            $ancestors[] = $current;
        }

        return $ancestors;
    }

    /**
     * 根据用户积分获取对应的星级
     * @param int $score 用户当前积分
     * @return int 返回对应的星级
     */
    private function getStarLevel($score)
    {
        // 修正阈值数组顺序（严格从高到低）
        $thresholds = [
            13 => 55080, 12 => 46080, 11 => 23040, 10 => 11520, 9 => 5760,
            8 => 2880, 7 => 1440, 6 => 720, 5 => 360,
            4 => 180, 3 => 90, 2 => 45, 1 => 171
        ];

        // 按值降序排序保证匹配顺序
        arsort($thresholds);

        foreach ($thresholds as $star => $limit) {
            if ($score >= $limit) {
                return $star;
            }
        }

        return 0;
    }

    private function getOrderStarLevel($order_goods_price)
    {
        // 修正阈值数组顺序（严格从高到低）
        // $thresholds = [
        //     13 => 61209, 12 => 51209, 11 => 25609, 10 => 12809, 9 => 6409,
        //     8 => 3209, 7 => 1609, 6 => 809, 5 => 409,
        //     4 => 209, 3 => 109, 2 => 59, 1 => 199
        // ];
        
          //变更为商品ID
        $thresholds = [
            13 => 24, 12 => 23, 11 => 22, 10 => 21, 9 => 20,
            8 => 19, 7 => 16, 6 => 9, 5 => 15,
            4 => 14, 3 => 13, 2 => 4, 1 => 11
        ];
        if(!in_array($order_goods_price,$thresholds)){
            return 0;
        }else{
            return array_search($order_goods_price,$thresholds);
        }
    }

    private function getOrderSubScore($level)
    {
        $thresholds = [
            13 => 38, 12 => 10, 11 => 20, 10 => 40, 9 => 80,
            8 => 560, 7 => 1120, 6 => 560, 5 => 80,
            4 => 40, 3 => 20, 2 => 10, 1 => 0,  0=>0
        ];
        if (array_key_exists($level, $thresholds)) {
            return $thresholds[$level];
        } else {
            return 0;
        }
    }

    /**
     * @param $user
     * @param $star_level
     * @param $score
     * @param $order_id
     * @return User|mixed
     * @throws \think\exception\DbException
     */
    private function promoteUserScore($user,$star_level,$score,$order_id = '',$name = ''){
            // 输入验证
        if (empty($user) || empty($star_level) || empty($score)) {
            throw new \InvalidArgumentException('Invalid input parameters');
        }

        $currentUser = $user;
        $firstIdPrefix = config('oem.FirstIdPrefix');

        while ($currentUser["id"] != $firstIdPrefix && (int)$currentUser["star"] < $star_level) {
            $nextUser = User::find($currentUser["pid"]);
            if (!$nextUser) {
                break; // 如果找不到上级用户，退出循环
            }
            $currentUser = $nextUser;
        }
        if ($currentUser["star"] >= $star_level) {
            $extra = db("user")->where('id', $currentUser["id"])->find();
            $extra["score"] = bcadd($extra["score"], $score, 2);

            $insert = [
                "user_id"       => $currentUser["id"],
                "money"         => $score,
                "before"        => $currentUser["money"],
                "after"         => bcadd($currentUser["money"],$score),
                "memo"          => $name." - ".$star_level.'星'.config('oem.UpgradeStarName'),
                "service_ids"   => "",
                "type"          => "upgrade",
                "createtime"    => time(),
            ];

            $memo = $name." - ".$star_level.'星'.config('oem.UpgradeStarName').",消耗可省钱额度!";
            db("user_money_save_log")
                ->insert([
                    'user_id' => $currentUser["id"],
                    'money' => $score,
                    'before' => $currentUser["save_money"],
                    'after' => ($currentUser["save_money"] - $score) < 0 ? 0 : bcsub($currentUser["save_money"],$score,2),
                    'memo' => $memo,
                    'type' => "dircet",
                    "createtime" => time()
                ]);

            if($currentUser["save_money"] - $score <= 0){
                db("user")
                    ->where("id",$currentUser["id"])
                    ->inc("money",$score)
                    ->inc("score",$score)
                    ->inc("blind_draw_money",$score)
                    ->inc("use_save_money",$currentUser["save_money"])
//                    ->dec("save_money",$score)
                    ->update(["updatetime"=>time(),"save_money"=>0]);
            }else{
                db("user")
                    ->where("id",$currentUser["id"])
                    ->inc("money",$score)
                    ->inc("score",$score)
                    ->inc("blind_draw_money",$score)
                    ->inc("use_save_money",$score)
                    ->dec("save_money",$score)
                    ->update(["updatetime"=>time()]);
            }

            db("user_money_log")->insert($insert);

//            $currentUser->score = bcadd($currentUser["score"], $score, 2);
//            UserService::getInstance()->money($score, $currentUser["id"], $name." - ".$star_level.'星'.config('oem.UpgradeStarName'), 'upgrade', $order_id);
//            $currentUser->money = bcadd($currentUser["money"], $score, 2);

//            $extra->save();
//            $currentUser->save();
        }
    }


    private function salesCommissions($user,$star_level,$score,$order_id = '',$name = ''){
        // 输入验证
        if (empty($user) || empty($star_level) || empty($score)) {
            throw new \InvalidArgumentException('Invalid input parameters');
        }

        $currentUser = $user;
        $firstIdPrefix = config('oem.FirstIdPrefix');

        while ($currentUser->id != $firstIdPrefix && (int)$currentUser->star < $star_level) {
            $nextUser = User::find($currentUser->direct_push);
            if (!$nextUser) {
                break; // 如果找不到上级用户，退出循环
            }
            $currentUser = $nextUser;
        }
        if ($currentUser->star >= $star_level) {
            $extra = UserExtra::where('user_id', $currentUser->id)->find();
            $extra->score = bcadd($extra->score, $score, 2);
            $currentUser->score = bcadd($currentUser->score, $score, 2);
            UserService::getInstance()->money(
                $score,
                $currentUser->id,
                $name." - ".$star_level."星".config('oem.DirectPushName'),
                'upgrade',
                $order_id
            );
            $currentUser->money = bcadd($currentUser->money, $score, 2);
            if($currentUser->save_money - $score <= 0){
                $currentUser->save_money = 0;
                $currentUser->use_save_money = bcadd($user["use_save_money"],$user["save_money"],2);
            }else{
                $currentUser->save_money = bcsub($currentUser->save_money, $score, 2);
                $currentUser->use_save_money = bcadd($user["use_save_money"],$score,2);
            }

            $memo =  $name." - ".$star_level."星".config('oem.DirectPushName').",消耗可省钱额度!";
            db("user_money_save_log")
                ->insert([
                    'user_id' => $user["id"],
                    'money' => $score,
                    'before' => $currentUser->save_money,
                    'after' => ($currentUser->save_money - $score) < 0 ? 0 : bcsub($currentUser->save_money,$score,2),
                    'memo' => $memo,
                    'type' => "dircet",
                    "createtime" => time()
                ]);

            $extra->save();
            $currentUser->save();
        }
    }

    private function upgradeAllOrder($user_id,$order_price)
    {
        try {
            $queue = [$user_id];
            while (!empty($queue)) {
                $current_user_id = array_shift($queue);
                $user = User::get($current_user_id);

                // 用户不存在的情况
                if (is_null($user)) {
                    continue;
                }

                // 更新用户订单总额
                $new_all_order = bcadd($user->all_order, $order_price, 2);
                $user->all_order = $new_all_order;

                // 使用数据库事务确保一致性
                $user->save();

                // 如果有上级用户，将其加入队列
                if ($user->pid != 0) {
                    $queue[] = $user->pid;
                }
            }
        } catch (\Exception $e) {
            // 异常处理与日志记录
            Log::error("Error upgrading all orders for user {$user_id}: " . $e->getMessage());
            throw $e; // 重新抛出异常以便上层处理
        }

    }
    
    private function updateUserPromotionMoney($uid,$money){
        $myLeaderIdArr = $this->getMyLeaderIdArr($uid);
        db("user")->where("id","in",$myLeaderIdArr)->where("lamp",1)->where("star",13)->inc("promotion_money",$money)->update(["updatetime"=>time()]);
    }

    private function getMyLeaderIdArr($uid,$arr = []){
        $user_id = db("user")->where("id",$uid)->field("id,direct_push")->find();
        if(!$user_id || $user_id["direct_push"] == 0){
            return $arr;
        }else{
            $arr[] = $user_id["direct_push"];
            return $this->getMyLeaderIdArr($user_id["direct_push"],$arr);
        }
    }
    
    
    public function normalPromote($order_id){
        try {
            // 检查订单是否存在
            $model_order = model('app\api\model\wanlshop\Order');
            $order_info = $model_order->find($order_id);
            //  排除Flagship店
            if (!$order_info || $order_info['shop_id'] == config('oem.OrderShopPrefix')) {
                return false;
            }

            // 获取目标分类下的商品ID列表
            $goods_category = model('app\api\model\wanlshop\Goods');
            $goods_ids = $goods_category
                ->whereNotIn('category_id',config('oem.CategoryIdNotLikePrefix'))
                ->column('id');

            if (!is_array($goods_ids)) {
                return true;
            }

            $goods_ids = array_values($goods_ids);
            if (empty($goods_ids)) {
                return true;
            }

            // 统计符合条件的商品总数量
            $model_order_goods = model('app\api\model\wanlshop\OrderGoods');
            // 计算应得积分
            $order_goods_price = $model_order_goods
                ->where('order_id', $order_info['id'])
                ->sum('price');

            $order_goods = $model_order_goods
                ->where('order_id', $order_info['id'])
                ->find();
            $goods = Goods::where('id', $order_goods['goods_id'])
                ->find();

            $user = User::get($order_info['user_id']);

            $get_order_star_level = $this->getNormalOrderStarLevel($user);


            $get_score = $this->getNormalOrderScore($goods,$order_goods_price);

            // 更新用户星级
            Db::startTrans();
            try {
                $user->normal_num = bcadd($user->normal_num, 1);
                $this->handleUpgradeNormalReward($get_order_star_level, $get_score, $order_info['id'], $user);
                $user->save();
                Db::commit();
            } catch (\Exception $e) {
                Db::rollback();
                Log::error("普通积分计算错误的原因:" . $e->getMessage());
                return false;
            }
            return true;
        } catch (\Exception $e) {
            Log::error("普通积分计算错误的原因: " . $e->getMessage().$e->getLine());
            return false;
        }
    }

    /**
     *  获取普通订单积分等级
     * @param $user
     * @return int
     * @throws \think\exception\DbException
     */
    private function getNormalOrderStarLevel($user): int
    {
        if (!$user) {
            return 0;
        }
        return ($user->normal_num % 13 + 13) % 13;  // 计算等级 13 为最大等级 进行循环反
    }

    /**
     * 获取普通订单积分
     * @param $goods
     * @param $order_goods_price
     * @return int|string
     */
    private function getNormalOrderScore($goods,$order_goods_price)
    {
        if (!$goods ||  empty($goods['discounts']) || !is_numeric($order_goods_price)) {
            return 0;
        }

        $discounts = (float)bcdiv($goods['discounts'], 100, 2);
        $price     = (float)$order_goods_price;
        if ($discounts <= 0 || $price <= 0) {
            return 0;
        }
        // 积分计算：商品让利的50%
        return bcmul('0.5', bcmul((string)$discounts, (string)$price, 2), 2);

    }

    /**
     * 处理普通积分奖励
     * @param $star_level
     * @param $score
     * @param $order_id
     * @param $user
     * @return void
     */
    private function handleUpgradeNormalReward($star_level, $score, $order_id, $user)
    {

        Db::startTrans();
        try {

            $user_extra = $this->currentUser($user, $star_level);
            if (!$user_extra) {
                Db::rollback();
                return;
            }
            $this->promoteNormalUserScore($user_extra, $star_level, $score, $order_id);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            Log::error("处理普通积分奖励错误的原因 (Order ID: {$order_id}): " . $e->getMessage().$e->getLine());
        }
    }

    /**
     * 处理普通积分奖励
     * @param $user
     * @param $star_level
     * @param $score
     * @param $order_id
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private function promoteNormalUserScore($user,$star_level,$score,$order_id = ''){
        // 输入验证
        if (empty($user) || empty($star_level) || empty($score)) {
            throw new \InvalidArgumentException('Invalid input parameters');
        }

        $currentUser = $user;
        $firstIdPrefix = config('oem.FirstIdPrefix');

        while ($currentUser->id != $firstIdPrefix && (int)$currentUser->star < $star_level) {
            $nextUser = User::find($currentUser->pid);
            if (!$nextUser) {
                break; // 如果找不到上级用户，退出循环
            }
            $currentUser = $nextUser;
        }
        if ($currentUser->star >= $star_level) {
            MoneyLog::create([
                'user_id' => $currentUser->id,
                'money' => $score, // 操作金额
                'before' => $currentUser->money, // 原金额
                'after' => bcadd($currentUser->money, $score, 2), // 增加后金额
                'memo' => '普通订单积分奖励', // 备注
                'type' => 'pay', // 类型
                'service_ids' => $order_id // 业务ID
            ]);
            $currentUser->score = bcadd($currentUser->score, $score, 2);
            $currentUser->money = bcadd($currentUser->money, $score, 2);
            $currentUser->save();
        }
    }

}
